{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 05自动微分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:31.627945Z",
     "iopub.status.busy": "2023-08-18T07:07:31.627424Z",
     "iopub.status.idle": "2023-08-18T07:07:32.686372Z",
     "shell.execute_reply": "2023-08-18T07:07:32.685559Z"
    },
    "origin_pos": 2,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([0., 1., 2., 3.])"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch\n",
    "\n",
    "x = torch.arange(4.0)\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true,
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:32.690633Z",
     "iopub.status.busy": "2023-08-18T07:07:32.689882Z",
     "iopub.status.idle": "2023-08-18T07:07:32.694159Z",
     "shell.execute_reply": "2023-08-18T07:07:32.693367Z"
    },
    "origin_pos": 7,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [],
   "source": [
    "x.requires_grad_(True)  # 等价于x=torch.arange(4.0,requires_grad=True)\n",
    "x.grad  # 默认值是None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:32.698006Z",
     "iopub.status.busy": "2023-08-18T07:07:32.697167Z",
     "iopub.status.idle": "2023-08-18T07:07:32.705385Z",
     "shell.execute_reply": "2023-08-18T07:07:32.704593Z"
    },
    "origin_pos": 12,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(28., grad_fn=<MulBackward0>)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = 2 * torch.dot(x, x)\n",
    "y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:32.708698Z",
     "iopub.status.busy": "2023-08-18T07:07:32.708196Z",
     "iopub.status.idle": "2023-08-18T07:07:32.713924Z",
     "shell.execute_reply": "2023-08-18T07:07:32.713091Z"
    },
    "origin_pos": 17,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([ 0.,  4.,  8., 12.])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y.backward()\n",
    "x.grad"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:32.718858Z",
     "iopub.status.busy": "2023-08-18T07:07:32.718156Z",
     "iopub.status.idle": "2023-08-18T07:07:32.724091Z",
     "shell.execute_reply": "2023-08-18T07:07:32.723104Z"
    },
    "origin_pos": 22,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([True, True, True, True])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.grad == 4 * x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:32.729368Z",
     "iopub.status.busy": "2023-08-18T07:07:32.728433Z",
     "iopub.status.idle": "2023-08-18T07:07:32.736493Z",
     "shell.execute_reply": "2023-08-18T07:07:32.735715Z"
    },
    "origin_pos": 27,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([1., 1., 1., 1.])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 在默认情况下，PyTorch会累积梯度，我们需要清除之前的值\n",
    "x.grad.zero_()\n",
    "y = x.sum()\n",
    "y.backward()\n",
    "x.grad"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:32.740109Z",
     "iopub.status.busy": "2023-08-18T07:07:32.739419Z",
     "iopub.status.idle": "2023-08-18T07:07:32.745803Z",
     "shell.execute_reply": "2023-08-18T07:07:32.744893Z"
    },
    "origin_pos": 32,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([0., 2., 4., 6.])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 对非标量调用backward需要传入一个gradient参数，该参数指定微分函数关于self的梯度。\n",
    "# 本例只想求偏导数的和，所以传递一个1的梯度是合适的\n",
    "x.grad.zero_()\n",
    "y = x * x\n",
    "# 等价于y.backward(torch.ones(len(x)))\n",
    "y.sum().backward()\n",
    "x.grad"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:32.749398Z",
     "iopub.status.busy": "2023-08-18T07:07:32.748759Z",
     "iopub.status.idle": "2023-08-18T07:07:32.755280Z",
     "shell.execute_reply": "2023-08-18T07:07:32.754543Z"
    },
    "origin_pos": 37,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([True, True, True, True])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.grad.zero_()\n",
    "y = x * x\n",
    "u = y.detach()\n",
    "z = u * x\n",
    "\n",
    "z.sum().backward()\n",
    "x.grad == u"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:32.759344Z",
     "iopub.status.busy": "2023-08-18T07:07:32.758633Z",
     "iopub.status.idle": "2023-08-18T07:07:32.764663Z",
     "shell.execute_reply": "2023-08-18T07:07:32.763922Z"
    },
    "origin_pos": 42,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([True, True, True, True])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.grad.zero_()\n",
    "y.sum().backward()\n",
    "x.grad == 2 * x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true,
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:32.769249Z",
     "iopub.status.busy": "2023-08-18T07:07:32.768616Z",
     "iopub.status.idle": "2023-08-18T07:07:32.773175Z",
     "shell.execute_reply": "2023-08-18T07:07:32.772293Z"
    },
    "origin_pos": 47,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [],
   "source": [
    "def f(a):\n",
    "    b = a * 2\n",
    "    while b.norm() < 1000:\n",
    "        b = b * 2\n",
    "    if b.sum() > 0:\n",
    "        c = b\n",
    "    else:\n",
    "        c = 100 * b\n",
    "    return c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true,
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:32.777740Z",
     "iopub.status.busy": "2023-08-18T07:07:32.777207Z",
     "iopub.status.idle": "2023-08-18T07:07:32.782254Z",
     "shell.execute_reply": "2023-08-18T07:07:32.781458Z"
    },
    "origin_pos": 52,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [],
   "source": [
    "a = torch.randn(size=(), requires_grad=True)\n",
    "d = f(a)\n",
    "d.backward()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2023-08-18T07:07:32.785728Z",
     "iopub.status.busy": "2023-08-18T07:07:32.785179Z",
     "iopub.status.idle": "2023-08-18T07:07:32.790672Z",
     "shell.execute_reply": "2023-08-18T07:07:32.789892Z"
    },
    "origin_pos": 57,
    "tab": [
     "pytorch"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(True)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.grad == d / a"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  },
  "required_libs": []
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
